use crate::dto;
use crate::dto::core::endpoint::EndpointItem;
use base64::Engine;
use serde::{Deserialize, Serialize};
use wanmesh_common::net::wireguard;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct EndpointInfo {
    #[serde(flatten)]
    pub inner: EndpointItem,
    pub srv6: dto::core::endpoint_srv6_config::EndpointSrv6Config,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub wireguard: Option<dto::core::endpoint_wireguard_config::EndpointWireguardConfig>,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub peers: Vec<dto::endpoint_peer::EndpointPeerInfo>,
}

impl TryFrom<&EndpointInfo> for wireguard::config::Config {
    type Error = anyhow::Error;

    fn try_from(value: &EndpointInfo) -> Result<Self, Self::Error> {
        let wireguard_config = match &value.wireguard {
            Some(v) => v,
            None => return Err(anyhow::anyhow!("wireguard未设置")),
        };

        let mut allowed_ips = Vec::new();
        if let Some(ip) = &value.inner.inner.ipv4 {
            allowed_ips.push(cidr::IpInet::V4(ip.address.clone()));
        }

        if let Some(ip) = &value.inner.inner.ipv6 {
            allowed_ips.push(cidr::IpInet::V6(ip.address.clone()));
        }

        let mut peers: Vec<wireguard::config::PeerConfig> = Vec::new();
        for peer in &value.peers {
            let p = peer.try_to_wireguard_config(allowed_ips.clone())?;
            peers.push(p);
        }

        let private_key =
            base64::prelude::BASE64_STANDARD.encode(&wireguard_config.config.interface.private_key);

        Ok(Self {
            interface: Some(wireguard::config::InterfaceConfig {
                private_key: Some(private_key),
            }),
            peers,
        })
    }
}
